#include "TCPClient.h"
#include <QPushButton>
#include <QLabel>
#include <QComboBox>
#include <QGroupBox>
#include <QTextEdit>
#include <QCheckBox>
#include <QSpinBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QTcpSocket>
#include <QSettings>
#include <QDebug>
#include <QDateTime>
#include <QTimer>

#include <QLineEdit>
#include <QHostAddress>

TCPClient::TCPClient(QWidget *parent) : QWidget(parent)
{
    initWidget();

    m_tcpSocket = new QTcpSocket(this);
    connect(m_tcpSocket, &QTcpSocket::connected, this, &TCPClient::slot_connected);
    connect(m_tcpSocket, &QTcpSocket::readyRead, this, &TCPClient::slot_readyRead);
    connect(m_tcpSocket, &QTcpSocket::disconnected, this, &TCPClient::slot_disconnected);

    QSettings settings("settings.ini", QSettings::IniFormat);
    settings.beginGroup("TCPClientSettings");
    QString targetIP = settings.value("TargetIP").toString();
    QString targetPort = settings.value("TargetPort").toString();
    settings.endGroup();
    m_ctrlTargetIP->setText(targetIP);
    m_ctrTargetPort->setText(targetPort);

    m_netSettings.sendHex = false;
    m_netSettings.showHex = false;
    m_netSettings.showTime = false;

    m_autoSendTimer = new QTimer(this);
    connect(m_autoSendTimer, &QTimer::timeout, this, &TCPClient::slot_netSend);

    slot_wordWrap(false);
    updateControlState();
}

TCPClient::~TCPClient()
{
    if(m_tcpSocket && QAbstractSocket::UnconnectedState != m_tcpSocket->state()){
        m_tcpSocket->disconnectFromHost();
        m_tcpSocket->deleteLater();
    }
}

void TCPClient::initWidget()
{
    QGroupBox *group_netSet = new QGroupBox("Net Settings", this);
    QGridLayout *layout_netSet = new QGridLayout(group_netSet);
    QLabel *lb_targetIP = new QLabel("Target IP", this);
    m_ctrlTargetIP = new QLineEdit(this);
    QLabel *lb_targetPort = new QLabel("Target Port", this);
    m_ctrTargetPort = new QLineEdit(this);
    m_btnOpen = new QPushButton("Connect", this);
    layout_netSet->addWidget(lb_targetIP, 0, 0);
    layout_netSet->addWidget(m_ctrlTargetIP, 0, 1);
    layout_netSet->addWidget(lb_targetPort, 1, 0);
    layout_netSet->addWidget(m_ctrTargetPort, 1, 1);
    layout_netSet->addWidget(m_btnOpen, 2, 0, 1, 2, Qt::AlignCenter);

    QGroupBox *group_recvSet = new QGroupBox("Recieve Settings", this);
    QGridLayout *layout_recvSet = new QGridLayout(group_recvSet);
    QCheckBox *check_hexRecv = new QCheckBox("Hex Recieve", this);
    QCheckBox *check_showTime = new QCheckBox("Show Time", this);
    QCheckBox *check_wordWrap = new QCheckBox("Word Wrap", this);
    layout_recvSet->addWidget(check_showTime, 0, 0);
    layout_recvSet->addWidget(check_hexRecv, 1, 0);
    layout_recvSet->addWidget(check_wordWrap, 2, 0);

    QGroupBox *group_sendSet = new QGroupBox("Send Settings", this);
    QGridLayout *layout_sendSet = new QGridLayout(group_sendSet);
    QCheckBox *check_hexSend = new QCheckBox("Hex Send", this);
    QCheckBox *check_autoSend = new QCheckBox("Auto Send", this);
    m_spinBoxSendMs = new QSpinBox(this);
    m_spinBoxSendMs->setSuffix(" ms");
    m_spinBoxSendMs->setRange(1, 9999);
    m_spinBoxSendMs->setValue(1000);
    layout_sendSet->addWidget(check_hexSend, 0, 0, 1, 2);
    layout_sendSet->addWidget(check_autoSend, 1, 0, 1, 1);
    layout_sendSet->addWidget(m_spinBoxSendMs, 1, 1, 1, 1);

    QPushButton *btn_clearRecv = new QPushButton("Clear Recieve", this);
    QPushButton *btn_clearSend = new QPushButton("Clear Send", this);
    QHBoxLayout *layout_clearBtns = new QHBoxLayout;
    layout_clearBtns->addWidget(btn_clearRecv);
    layout_clearBtns->addWidget(btn_clearSend);

    QVBoxLayout *layout_settings = new QVBoxLayout;
    layout_settings->addWidget(group_netSet);
    layout_settings->addWidget(group_recvSet);
    layout_settings->addWidget(group_sendSet);
    layout_settings->addLayout(layout_clearBtns);
    layout_settings->addStretch(1);

    QGroupBox *group_recv = new QGroupBox("Recieve Data", this);
    QGridLayout *layout_recv = new QGridLayout(group_recv);
    m_textRecv = new QTextEdit(this);
    layout_recv->addWidget(m_textRecv);
    m_textRecv->setReadOnly(true);

    QGroupBox *group_send = new QGroupBox("Send Data", this);
    QGridLayout *layou_send = new QGridLayout(group_send);
    m_textSend = new QTextEdit(this);
    m_btnSend = new QPushButton("Send", this);
    layou_send->addWidget(m_textSend, 0, 0);
    layou_send->addWidget(m_btnSend, 0, 1);
    layou_send->setColumnStretch(0, 1);
    m_textSend->setMaximumHeight(80);

    QGridLayout *layout_surface = new QGridLayout(this);
    layout_surface->addLayout(layout_settings, 0, 0, 2, 1);
    layout_surface->addWidget(group_recv, 0, 1, 1, 1);
    layout_surface->addWidget(group_send, 1, 1, 1, 1);
    layout_surface->setRowStretch(0, 1);
    layout_surface->setColumnStretch(1, 1);

    connect(m_btnOpen, &QPushButton::clicked, this, &TCPClient::slot_netOpen);
    connect(m_btnSend, &QPushButton::clicked, this, &TCPClient::slot_netSend);
    connect(check_hexRecv, &QCheckBox::stateChanged, this, &TCPClient::slot_hexRecieve);
    connect(check_showTime, &QCheckBox::stateChanged, this, &TCPClient::slot_showTime);
    connect(check_wordWrap, &QCheckBox::stateChanged, this, &TCPClient::slot_wordWrap);
    connect(check_hexSend, &QCheckBox::stateChanged, this, &TCPClient::slot_hexSend);
    connect(check_autoSend, &QCheckBox::stateChanged, this, &TCPClient::slot_autoSend);
    connect(btn_clearRecv, &QPushButton::clicked, m_textRecv, &QTextEdit::clear);
    connect(btn_clearSend, &QPushButton::clicked, m_textSend, &QTextEdit::clear);
}

void TCPClient::addLog(QString log)
{
    if(m_netSettings.showTime){
        log = QDateTime::currentDateTime().toString("yyyy/MM/dd hh:mm:ss:zzz: ") + log;
    }
    m_textRecv->append(log);
}

void TCPClient::slot_netOpen()
{
    if(QAbstractSocket::ConnectedState != m_tcpSocket->state()){
        QString targetIP = m_ctrlTargetIP->text().simplified();
        QString targetPort = m_ctrTargetPort->text().simplified();
        if(targetIP.isEmpty() || targetPort.isEmpty()){
            addLog("Target IP Or Port Cannot Be Empty.");
        }
        else{
            m_tcpSocket->connectToHost(QHostAddress(targetIP), targetPort.toUInt());
            if(m_tcpSocket->waitForConnected(1000)){
                addLog("Net Open Succeed.");
                QSettings settings("settings.ini", QSettings::IniFormat);
                settings.beginGroup("TCPClientSettings");
                settings.setValue("TargetIP", targetIP);
                settings.setValue("TargetPort", targetPort);
                settings.endGroup();

                QString curIP = m_tcpSocket->localAddress().toString();
                QString curPort = QString::number(m_tcpSocket->localPort());
                emit signalUpdateTitle(QString("TCPClient-%1:%2").arg(curIP).arg(curPort));
            }
            else{
                addLog("Net Open Failed: " + m_tcpSocket->errorString());
            }
        }
    }
    else{
        addLog("Net Close Succeed.");
        m_tcpSocket->disconnectFromHost();
    }
}

void TCPClient::updateControlState()
{
    bool state = (QAbstractSocket::ConnectedState == m_tcpSocket->state());
    m_ctrlTargetIP->setEnabled(!state);
    m_ctrTargetPort->setEnabled(!state);
    m_btnOpen->setText(state ? "Disconnect" : "Connect");
    m_btnSend->setEnabled(state);
}

void TCPClient::slot_connected()
{
    addLog("connected");
    updateControlState();
}

void TCPClient::slot_disconnected()
{
    addLog("disconnected");
    updateControlState();
}

void TCPClient::slot_readyRead()
{
    QByteArray data(m_tcpSocket->readAll());
    if(m_netSettings.showHex){
        addLog(data.toHex(' '));
    }
    else{
        addLog(QString::fromLocal8Bit(data));
    }
}

void TCPClient::slot_netSend()
{
    if(!m_tcpSocket->isWritable()){
        return;
    }

    QString text = m_textSend->toPlainText();
    if(text.isEmpty()){
        return;
    }

    QByteArray data = text.toLocal8Bit();
    if(m_netSettings.sendHex){
        data = QByteArray::fromHex(data);
    }
    m_tcpSocket->write(data);
    addLog(text);
}

void TCPClient::slot_hexRecieve(int state)
{
    m_netSettings.showHex = (Qt::Checked == state);
}

void TCPClient::slot_showTime(int state)
{
    m_netSettings.showTime = (Qt::Checked == state);
}

void TCPClient::slot_wordWrap(int state)
{
    m_textRecv->setWordWrapMode(Qt::Checked == state ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap);
}

void TCPClient::slot_hexSend(int state)
{
    m_netSettings.sendHex = (Qt::Checked == state);
}

void TCPClient::slot_autoSend(int state)
{
    bool autoSend(Qt::Checked == state);
    if(autoSend){
        m_autoSendTimer->setInterval(m_spinBoxSendMs->value());
        m_autoSendTimer->start();
    }
    else{
        m_autoSendTimer->stop();
    }
    m_spinBoxSendMs->setEnabled(!autoSend);
}
